﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Grafica1
{
    public class MyDrowableFrustum
    {
        public VertexPositionColor[] StartRing;
        public VertexPositionColor[] EndRing;
        public IEnumerable<VertexPositionColor>[] rings;
        public VertexBuffer startBuffer;
        public VertexBuffer endBuffer;
        public VertexBuffer[] ringsBuffer;
        public VertexBuffer zBuffer;
        public IndexBuffer zIBuffer;
        public static Vector3[] tipicRing = new Vector3[] { new Vector3(1, 1, 0), new Vector3(1, -1, 0), new Vector3(-1, -1, 0), new Vector3(-1, 1, 0), new Vector3(1, 1, 0) };

        public MyDrowableFrustum(Color startColor, Color endColor)
        {
            int nAnelli = Consts.NUM_ANELLI;
            int zrows = Consts.NUM_Z_ROW;

            // partiamo dagli edges del frustum

            var startRing = new Vector3[4 * (zrows + 1) + 1];

            startRing[0 * (zrows + 1)] = tipicRing[0];
            startRing[1 * (zrows + 1)] = tipicRing[1];
            startRing[2 * (zrows + 1)] = tipicRing[2];
            startRing[3 * (zrows + 1)] = tipicRing[3];
            startRing[4 * (zrows + 1)] = tipicRing[4];

            //creiamo le linee parallele a z
            for (int i = 1; i <= zrows; i++)
            {
                for (int c = 0; c <= zrows; c++)
                {
                    startRing[i + (c * (zrows + 1))] = Vector3.Lerp(startRing[c * (zrows + 1)], startRing[(c + 1) * (zrows + 1)], (float)i / (float)(zrows + 1));
                }
            }

            //creiamo l'ultimo anello
            EndRing = (from pt in startRing select new VertexPositionColor(new Vector3(pt.X, pt.Y, 1),endColor)).ToArray();

            //creiamo e trasformiamo gli anelli intermedi
            rings = (from ct in Enumerable.Range(1, nAnelli - 1)
                     let pass = (float)ct / (float)nAnelli
                     let color = Color.Lerp(startColor, endColor, pass)
                     let tring = (from pt in tipicRing select new Vector3(pt.X, pt.Y, MathHelper.Lerp(0, 1, pass)))
                     select (from trpt in tring select new VertexPositionColor(trpt, color))).ToArray();
            //trasformiamo gli altri
            StartRing = (from pt in startRing
                         select new VertexPositionColor(pt, startColor)).ToArray();
        }

        public void LoadContent(GraphicsDevice graphics)
        {
            startBuffer = new VertexBuffer(graphics, VertexPositionColor.VertexDeclaration, StartRing.Count(), BufferUsage.WriteOnly);
            startBuffer.SetData(StartRing);
            endBuffer = new VertexBuffer(graphics, VertexPositionColor.VertexDeclaration, EndRing.Count(), BufferUsage.WriteOnly);
            endBuffer.SetData(EndRing);
            ringsBuffer = new VertexBuffer[rings.Count()];
            for (int i = 0; i < ringsBuffer.Count(); i++)
            {
                ringsBuffer[i] = new VertexBuffer(graphics, VertexPositionColor.VertexDeclaration, rings[i].Count(), BufferUsage.WriteOnly);
                ringsBuffer[i].SetData(rings[i].ToArray());
            }
            var tmp = new VertexPositionColor[2 * (4 * (Consts.NUM_Z_ROW + 1))];
            zBuffer = new VertexBuffer(graphics, VertexPositionColor.VertexDeclaration, tmp.Length, BufferUsage.WriteOnly);
            for (int i = 0; i < StartRing.Length - 1; i++)
            {
                tmp[2 * i] = StartRing[i];
                tmp[2 * i + 1] = EndRing[i];
            }
            zBuffer.SetData(tmp);
            zIBuffer = new IndexBuffer(graphics, IndexElementSize.SixteenBits, tmp.Length, BufferUsage.WriteOnly);
            zIBuffer.SetData((from x in Enumerable.Range(0, tmp.Length) select (Int16) x).ToArray());
        }

        public void Draw(GraphicsDevice GraphicsDevice, Effect fx, Matrix world, Matrix view, Matrix projection)
        {

            fx.Parameters["World"].SetValue(world);
            fx.Parameters["View"].SetValue(view);
            fx.Parameters["Projection"].SetValue(projection);
            fx.CurrentTechnique.Passes[0].Apply();

            GraphicsDevice.SetVertexBuffer(startBuffer);
            GraphicsDevice.DrawPrimitives(PrimitiveType.LineStrip, 0, startBuffer.VertexCount - 1);

            GraphicsDevice.SetVertexBuffer(endBuffer);
            GraphicsDevice.DrawPrimitives(PrimitiveType.LineStrip, 0, endBuffer.VertexCount- 1);

            foreach (var ringBuffer in ringsBuffer)
            {
                GraphicsDevice.SetVertexBuffer(ringBuffer);
                GraphicsDevice.DrawPrimitives(PrimitiveType.LineStrip, 0, ringBuffer.VertexCount - 1);
            }

            GraphicsDevice.SetVertexBuffer(zBuffer);
            GraphicsDevice.Indices = zIBuffer;
            GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.LineList, 0, 0, zBuffer.VertexCount, 0, zBuffer.VertexCount / 2);


        }

    }
}

//        protected void drawCamera(Matrix actualView, VertexBuffer vb, int activeCamera)
//{

//Color cameraColor = Color.Red;
//switch (activeCamera)
//{

//case 0:
//cameraColor =

//Color.Red;
//break;
//case 1:
//cameraColor =

//Color.Yellow;
//break;
//}

//vpc =

//new VertexPositionColor[cameraPoints];
//bf =

//new BoundingFrustum(actualView * projection);
//var corners = bf.GetCorners();
//float max = (cameraPoints - 32) / 8;
//for (int j = 0; j < max; j++)
//{

//float lerpValue = j / max;
//if (relativeLerp) lerpValue /= 10;
//vpc[j * 8] =

//new VertexPositionColor(Vector3.Lerp(corners[0], corners[4], lerpValue), cameraColor);
//vpc[j * 8 + 1] =

//new VertexPositionColor(Vector3.Lerp(corners[1], corners[5], lerpValue), cameraColor);
//vpc[j * 8 + 2] =

//new VertexPositionColor(Vector3.Lerp(corners[1], corners[5], lerpValue), cameraColor);
//vpc[j * 8 + 3] =

//new VertexPositionColor(Vector3.Lerp(corners[2], corners[6], lerpValue), cameraColor);
//vpc[j * 8 + 4] =

//new VertexPositionColor(Vector3.Lerp(corners[2], corners[6], lerpValue), cameraColor);
//vpc[j * 8 + 5] =

//new VertexPositionColor(Vector3.Lerp(corners[3], corners[7], lerpValue), cameraColor);
//vpc[j * 8 + 6] =

//new VertexPositionColor(Vector3.Lerp(corners[3], corners[7], lerpValue), cameraColor);
//vpc[j * 8 + 7] =

//new VertexPositionColor(Vector3.Lerp(corners[0], corners[4], lerpValue), cameraColor);
//}

//for (int i = 0; i < 4; i++)
//{

//float lerpValue = (float)i / 3;
//vpc[(i * 8) + ((

//int)max * 8)] = new VertexPositionColor(Vector3.Lerp(corners[0], corners[1], lerpValue), cameraColor);
//vpc[(i * 8) + ((

//int)max * 8) + 1] = new VertexPositionColor(Vector3.Lerp(corners[4], corners[5], lerpValue), cameraColor);
//vpc[(i * 8) + ((

//int)max * 8) + 2] = new VertexPositionColor(Vector3.Lerp(corners[1], corners[2], lerpValue), cameraColor);
//vpc[(i * 8) + ((

//int)max * 8) + 3] = new VertexPositionColor(Vector3.Lerp(corners[5], corners[6], lerpValue), cameraColor);
//vpc[(i * 8) + ((

//int)max * 8) + 4] = new VertexPositionColor(Vector3.Lerp(corners[2], corners[3], lerpValue), cameraColor);
//vpc[(i * 8) + ((

//int)max * 8) + 5] = new VertexPositionColor(Vector3.Lerp(corners[6], corners[7], lerpValue), cameraColor);
//vpc[(i * 8) + ((

//int)max * 8) + 6] = new VertexPositionColor(Vector3.Lerp(corners[3], corners[0], lerpValue), cameraColor);
//vpc[(i * 8) + ((

//int)max * 8) + 7] = new VertexPositionColor(Vector3.Lerp(corners[7], corners[4], lerpValue), cameraColor);
//}

//vb.SetData(vpc);

//}

//        if (camera.Equals(camera_right))
//                {
//                    eff.Parameters["World"].SetValue(Matrix.Invert(camera_left.Projection) * Matrix.Invert(camera_left.View));
//                    GraphicsDevice.Vertices[0].SetSource(punti, 0, VertexPositionColor.SizeInBytes);
//                    eff.CommitChanges();
//                    GraphicsDevice.DrawPrimitives(PrimitiveType.LineStrip, 0, punti_data.Length - 1);
//                }

//                if (camera.Equals(camera_left))
//                {
//                    eff.Parameters["World"].SetValue(Matrix.Invert(camera_right.Projection) * Matrix.Invert(camera_right.View));
//                    GraphicsDevice.Vertices[0].SetSource(punti, 0, VertexPositionColor.SizeInBytes);
//                    eff.CommitChanges();
//                    GraphicsDevice.DrawPrimitives(PrimitiveType.LineStrip, 0, punti_data.Length - 1);
//                }
//    }
//}
